/*
 * =====================================================================================
 *
 *       Filename:  libnyb-net_interface.c
 *
 *    Description:  network interface get and set functions
 *
 *        Version:  1.0
 *        Created:  2018年12月17日 16时05分23秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  YOUR NAME (), 
 *   Organization:  
 *
 * =====================================================================================
 */
#include "libnyb-net.h"


/*
 * 如果缓冲区不够怎么办?
 *      只会取出部分的网卡信息
 */

int get_all_interfaces()
{
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd < 0) {
        perror("socket()");
        return -1;
    }
    struct ifconf _ifconf;
    struct ifreq  _ifreq[10];
    _ifconf.ifc_len = 10 * sizeof(struct ifreq);
    _ifconf.ifc_buf = (char *)_ifreq;

    if(ioctl(fd, SIOCGIFCONF, (char *)&_ifconf) < 0) {
        perror("ioctl(SIOCGIFCONF)");
        close(fd);
        return -1;
    }
    int i;
    int len = _ifconf.ifc_len/sizeof(struct ifreq);
    for(i = 0; i < len; i++) {
        printf("Interface: %s\n", _ifreq[i].ifr_name);

        if(ioctl(fd, SIOCGIFADDR, &_ifreq[i]) < 0) {
            perror("ioctl(SIOCGIFADDR)");
        }
        else {
            printf("\tIP: %s\n", inet_ntoa(((struct sockaddr_in *)(&_ifreq[i].ifr_addr))->sin_addr));
        }


        if(ioctl(fd, SIOCGIFDSTADDR, &_ifreq[i]) < 0) {
            perror("ioctl(SIOCGIFDSTADDR)");
        }
        else {
            printf("\tDSTIP: %s\n", inet_ntoa(((struct sockaddr_in *)(&_ifreq[i].ifr_dstaddr))->sin_addr));
        }

        if(ioctl(fd, SIOCGIFBRDADDR, &_ifreq[i]) < 0) {
            perror("ioctl(SIOCGIFBRDADDR)");
        }
        else {
            printf("\tBROADCAST: %s\n", inet_ntoa(((struct sockaddr_in *)(&_ifreq[i].ifr_broadaddr))->sin_addr));
        }

        if(ioctl(fd, SIOCGIFNETMASK, &_ifreq[i]) < 0) {
            perror("ioctl(SIOCGIFNETMASK)");
        }
        else {
            printf("\tNETMASK: %s\n", inet_ntoa(((struct sockaddr_in *)(&_ifreq[i].ifr_netmask))->sin_addr));
        }

        if(ioctl(fd, SIOCGIFMETRIC, &_ifreq[i]) < 0) {
            perror("ioctl(SIOCGIFMETRIC)");
        }
        else {
            printf("\tMETRIC: %d\n", _ifreq[i].ifr_metric);
        }

        if(ioctl(fd, SIOCGIFMTU, &_ifreq[i]) < 0) {
            perror("ioctl(SIOCGIFMTU)");
        }
        else {
            printf("\tMTU: %d\n", _ifreq[i].ifr_mtu);
        }

        if(ioctl(fd, SIOCGIFHWADDR, &_ifreq[i]) < 0) {
            perror("ioctl(SIOCGIFHWADDR)");
        }
        else {
            //MAC输出格式不正常，加上 & 0xff取出一个字节
            //不加 & 0xff为什么输出不正常呢?
            printf("\tMAC: %02X:%02X:%02X:%02X:%02X:%02X\n", 
                    _ifreq[i].ifr_hwaddr.sa_data[0] & 0xff,
                    _ifreq[i].ifr_hwaddr.sa_data[1] & 0xff,
                    _ifreq[i].ifr_hwaddr.sa_data[2] & 0xff,
                    _ifreq[i].ifr_hwaddr.sa_data[3] & 0xff,
                    _ifreq[i].ifr_hwaddr.sa_data[4] & 0xff,
                    _ifreq[i].ifr_hwaddr.sa_data[5] & 0xff);
        }

        if(ioctl(fd, SIOCGIFFLAGS, &_ifreq[i]) < 0) {
            perror("ioctl(SIOCGIFFLAGS)");
        }
        else {
            printf("\tFLAGS: %d\n", _ifreq[i].ifr_flags);
        }

        printf("\n");
    }
    return 0;
}

/*
 * return:
 *  -1: error
 *   0: ok
 */
int get_eth_ip(const char *eth_name, char *ip, int len)
{
    if(NULL == eth_name || NULL == ip || len < LEN_IP_STR) {
        fprintf(stderr, "get_eth_ip() arguments error!");
        return -1;
    }
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd < 0) {
        perror("socket()");
        return -1;
    }
    struct ifreq  _ifreq;
    memset(&_ifreq, 0, sizeof(_ifreq));
    strncpy(_ifreq.ifr_name, eth_name, sizeof(_ifreq.ifr_name));


    fprintf(stdout, "Interface: %s\n", _ifreq.ifr_name);

    if(ioctl(fd, SIOCGIFADDR, &_ifreq) < 0) {
        perror("ioctl(SIOCGIFADDR)");
        return -1;
    }
    else {
        strncpy(ip, inet_ntoa(((struct sockaddr_in *)(&_ifreq.ifr_addr))->sin_addr), len);
        fprintf(stdout, "\tIP: %s\n", ip);
        return 0;
    }
}

/*
 * return:
 *  -1: error
 *   0: ok
 */
int get_eth_mask(const char *eth_name, char *mask, int len)
{
    if(NULL == eth_name || NULL == mask || len < LEN_IP_STR) {
        fprintf(stderr, "get_eth_mask() arguments error!");
        return -1;
    }
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd < 0) {
        perror("socket()");
        return -1;
    }
    struct ifreq  _ifreq;
    memset(&_ifreq, 0, sizeof(_ifreq));
    strncpy(_ifreq.ifr_name, eth_name, sizeof(_ifreq.ifr_name));


    fprintf(stdout, "Interface: %s\n", _ifreq.ifr_name);

    if(ioctl(fd, SIOCGIFNETMASK, &_ifreq) < 0) {
        perror("ioctl(SIOCGIFADDR)");
        return -1;
    }
    else {
        strncpy(mask, inet_ntoa(((struct sockaddr_in *)(&_ifreq.ifr_netmask))->sin_addr), len);
        fprintf(stdout, "\tMASK: %s\n", mask);
        return 0;
    }
}

/*
 * return:
 *  -1: error
 *   0: ok
 */
int get_eth_broadcast(const char *eth_name, char *broadcast, int len)
{
    if(NULL == eth_name || NULL == broadcast || len < LEN_IP_STR) {
        fprintf(stderr, "get_eth_broadcast() arguments error!");
        return -1;
    }
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd < 0) {
        perror("socket()");
        return -1;
    }
    struct ifreq  _ifreq;
    memset(&_ifreq, 0, sizeof(_ifreq));
    strncpy(_ifreq.ifr_name, eth_name, sizeof(_ifreq.ifr_name));


    fprintf(stdout, "Interface: %s\n", _ifreq.ifr_name);

    if(ioctl(fd, SIOCGIFBRDADDR, &_ifreq) < 0) {
        perror("ioctl(SIOCGIFADDR)");
        return -1;
    }
    else {
        strncpy(broadcast, inet_ntoa(((struct sockaddr_in *)(&_ifreq.ifr_broadaddr))->sin_addr), len);
        fprintf(stdout, "\tBROADCAST: %s\n", broadcast);
        return 0;
    }
}

/*
 * return:
 *  -1: error
 *   0: ok
 */
int get_eth_mac(const char *eth_name, char *mac, int len)
{
    if(NULL == eth_name || NULL == mac || len < LEN_MAC_STR) {
        fprintf(stderr, "get_eth_mac() arguments error!");
        return -1;
    }
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd < 0) {
        perror("socket()");
        return -1;
    }
    struct ifreq  _ifreq;
    memset(&_ifreq, 0, sizeof(_ifreq));
    strncpy(_ifreq.ifr_name, eth_name, sizeof(_ifreq.ifr_name));


    fprintf(stdout, "Interface: %s\n", _ifreq.ifr_name);

    if(ioctl(fd, SIOCGIFHWADDR, &_ifreq) < 0) {
        perror("ioctl(SIOCGIFADDR)");
        return -1;
    }
    else {
        snprintf((char *)mac, len, "%02X:%02X:%02X:%02X:%02X:%02X", 
                _ifreq.ifr_hwaddr.sa_data[0] & 0xff,
                _ifreq.ifr_hwaddr.sa_data[1] & 0xff,
                _ifreq.ifr_hwaddr.sa_data[2] & 0xff,
                _ifreq.ifr_hwaddr.sa_data[3] & 0xff,
                _ifreq.ifr_hwaddr.sa_data[4] & 0xff,
                _ifreq.ifr_hwaddr.sa_data[5] & 0xff);
        fprintf(stdout, "\tMAC: %s\n", mac); 
        return 0;
    }
}


/*
 * return:
 *  -1: error
 *   0: ok
 */
int get_eth_dstip(const char *eth_name, char *dstip, int len)
{
    if(NULL == eth_name || NULL == dstip || len < LEN_IP_STR) {
        fprintf(stderr, "get_eth_dstip() arguments error!");
        return -1;
    }
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd < 0) {
        perror("socket()");
        return -1;
    }
    struct ifreq  _ifreq;
    memset(&_ifreq, 0, sizeof(_ifreq));
    strncpy(_ifreq.ifr_name, eth_name, sizeof(_ifreq.ifr_name));


    fprintf(stdout, "Interface: %s\n", _ifreq.ifr_name);

    if(ioctl(fd, SIOCGIFDSTADDR, &_ifreq) < 0) {
        perror("ioctl(SIOCGIFADDR)");
        return -1;
    }
    else {
        strncpy(dstip, inet_ntoa(((struct sockaddr_in *)(&_ifreq.ifr_netmask))->sin_addr), len);
        fprintf(stdout, "\tDSTIP: %s\n", dstip);
        return 0;
    }
}


/*
 * return:
 *  -1: error
 *  >=0: ok
 */
int get_eth_metric(const char *eth_name)
{
    if(NULL == eth_name) {
        fprintf(stderr, "get_eth_metric() arguments error!");
        return -1;
    }
    int metric = -1;
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd < 0) {
        perror("socket()");
        return -1;
    }
    struct ifreq  _ifreq;
    memset(&_ifreq, 0, sizeof(_ifreq));
    strncpy(_ifreq.ifr_name, eth_name, sizeof(_ifreq.ifr_name));


    fprintf(stdout, "Interface: %s\n", _ifreq.ifr_name);

    if(ioctl(fd, SIOCGIFMETRIC, &_ifreq) < 0) {
        perror("ioctl(SIOCGIFADDR)");
    }
    else {
        metric = _ifreq.ifr_metric;
        fprintf(stdout, "\tMETRIC: %d\n", metric);
    }
    close(fd);
    return metric;
}


/*
 * return:
 *  -1: error
 *  >=0: ok
 */
int get_eth_mtu(const char *eth_name)
{
    if(NULL == eth_name) {
        fprintf(stderr, "get_eth_mtu() arguments error!");
        return -1;
    }
    int mtu = -1;
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd < 0) {
        perror("socket()");
        return -1;
    }
    struct ifreq  _ifreq;
    memset(&_ifreq, 0, sizeof(_ifreq));
    strncpy(_ifreq.ifr_name, eth_name, sizeof(_ifreq.ifr_name));


    fprintf(stdout, "Interface: %s\n", _ifreq.ifr_name);

    if(ioctl(fd, SIOCGIFMTU, &_ifreq) < 0) {
        perror("ioctl(SIOCGIFADDR)");
    }
    else {
        mtu = _ifreq.ifr_mtu;
        fprintf(stdout, "\tMTU: %d\n", mtu);
    }
    close(fd);
    return mtu;
}


/*
 * return:
 *  <=0: error
 *  >0: ok
 */
short get_eth_flags(const char *eth_name)
{
    if(NULL == eth_name) {
        fprintf(stderr, "get_eth_flags() arguments error!");
        return -1;
    }
    short flags = -1;
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd < 0) {
        perror("socket()");
        return -1;
    }
    struct ifreq  _ifreq;
    memset(&_ifreq, 0, sizeof(_ifreq));
    strncpy(_ifreq.ifr_name, eth_name, sizeof(_ifreq.ifr_name));


    fprintf(stdout, "Interface: %s\n", _ifreq.ifr_name);

    if(ioctl(fd, SIOCGIFFLAGS, &_ifreq) < 0) {
        perror("ioctl(SIOCGIFADDR)");
    }
    else {
        flags = _ifreq.ifr_flags;
        fprintf(stdout, "\tFLAGS: %d\n", flags);
    }
    close(fd);
    return flags;
}


